package com.findme.test.xml;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;

/**
 * @ClassName: FileUtil
 * @description: NIO文件操作工具类
 * @author: find me
 * @create: 2022-03-01 13:42
 * @Version 1.0
 */
@Slf4j
public class FileUtil {

    /**
     * NIO读取文件
     *
     * @param allocate 设置缓冲区 长度
     * @param filePath 设置读取的文件路径 长度
     */
    public static String nioRead(int allocate, String filePath) throws Exception {
        // 1. r 	打开文件仅仅是为了读取数据，如果尝试调用任何写入数据的操作都会造成返回IOException错误信息的问题。
        // 2. rw    打开文件用于读写两种操作，如果文件本身并不存在，则会创建一个全新的文件。
        // 3. rwd   打开文件用于读写两种操作，这点和”rw“的操作完全一致，但是只会在cache满挥着调用RandomAccessFile.close()的时候才会执行内容同步操作。
        // 4. rws   在"rwd"的基础上对内容同步的要求更加严苛，每write修改一个byte都会直接修改到磁盘中。
        try (RandomAccessFile access = new RandomAccessFile(filePath, "r");) {
            StringBuffer sb = new StringBuffer();
            //  获取流的管道
            FileChannel channel = access.getChannel();
            // 此方法将容量(以字节为单位)作为参数。  分配一个新的字节缓冲区。
            ByteBuffer byteBuffer = ByteBuffer.allocate(allocate);
            //  此方法将以char为单位的新缓冲区的容量作为参数。
            CharBuffer charBuffer = CharBuffer.allocate(allocate);
            //  文件编码
            Charset charset = Charset.forName("UTF-8");
            // 读取文件编码
            CharsetDecoder decoder = charset.newDecoder();
            // 从管道中读取指定字节长度
            int length = channel.read(byteBuffer);
            while (length != -1) {
                // 将Buffer从写模式切换到读模式（必须调用这个方法）
                // 使缓冲区准备好新的通道写入或相对获取操作序列：它将限制设置为当前位置，然后将位置设置为零。
                byteBuffer.flip();
                // 从给定的输入缓冲区解码尽可能多的字节，将结果写入给定的输出缓冲区。
                decoder.decode(byteBuffer, charBuffer, true);
                charBuffer.flip();
                sb.append(charBuffer.toString());
                // 清空缓存
                // 使缓冲区准备好新的通道写入或相对获取操作序列：它将限制设置为当前位置，然后将位置设置为零。
                byteBuffer.clear();
                charBuffer.clear();
                // 再次读取文本内容
                length = channel.read(byteBuffer);
            }
            return sb.toString();
        } catch (IOException e) {
            throw new Exception("NotifyResultCode.EBDCPRE006");
        }

    }

    /**
     * NIO写文件
     *
     * @param context 字符串
     * @param chartName 文本格式
     * @param filePath 文本路径
     */
    public static void nioWrite(String context, int allocate, @NonNull String chartName,
            String filePath) throws Exception {
        File file = new File(filePath);
        if (file.exists()) {
        } else {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
        }
        try (FileOutputStream outputStream = new FileOutputStream(filePath,
                true); //文件内容追加模式--推荐
                FileChannel outChannel = outputStream.getChannel()) {

            byte[] bytes = context.getBytes();
            ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
            byteBuffer.put(context.getBytes(chartName));
            byteBuffer.flip();
            outChannel.write(byteBuffer);
        } catch (IOException e) {
            log.error("文件写入磁盘失败,异常原因{}", e.getMessage());
            throw new Exception("NotifyResultCode.EBDCPRE005");
        }
    }

    /**
     * nio事实现文件拷贝
     *
     * @param source 源地址
     * @param target 目标地址
     */
    public static void nioCopy(String source, String target, int allocate) throws Exception {

        File file = new File(target);
        if (file.exists()) {
        } else {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
        }
        try (FileInputStream inputStream = new FileInputStream(source);
                FileChannel inChannel = inputStream.getChannel();
                FileOutputStream outputStream = new FileOutputStream(target);
                FileChannel outChannel = outputStream.getChannel()) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(allocate);

            int length = inChannel.read(byteBuffer);
            while (length != -1) {
                byteBuffer.flip();//读取模式转换写入模式
                outChannel.write(byteBuffer);
                byteBuffer.clear(); //清空缓存，等待下次写入
                // 再次读取文本内容
                length = inChannel.read(byteBuffer);
            }
        } catch (IOException e) {
            throw new Exception("NotifyResultCode.EBDCPRE007");
        }

    }

    /**
     * 根据路径删除指定的目录或文件，无论存在与否
     *
     * @param sPath 要删除的目录或文件
     * @return 删除成功返回 true，否则返回 false。
     */
    public static boolean DeleteFolder(String sPath) {
        Boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        // 不存在返回 false
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 重命名文件
     *
     * @param oldFileName 旧文件名
     * @param newFileName 新文件名
     */
    public static void renameFile(String oldFileName, String newFileName) {
        File oldFile = new File(oldFileName);
        File newFile = new File(newFileName);
        if (newFile.exists() && newFile.isFile()) {
            FileUtil.DeleteFolder(newFileName);
        }
        if (oldFile.exists() && oldFile.isFile()) {
            oldFile.renameTo(newFile);
        }
    }

//    /**
//     * IO方法实现文件k拷贝
//     *
//     * @param sourcePath 源目录，根目录
//     */
//    private static void traditionalCopy(String sourcePath, String destPath) throws Exception {
//        File source = new File(sourcePath);
//        File dest = new File(destPath);
//        if (!dest.exists()) {
//            dest.createNewFile();
//        }
//        FileInputStream fis = new FileInputStream(source);
//        FileOutputStream fos = new FileOutputStream(dest);
//        byte[] buf = new byte[1024];
//        int len = 0;
//        while ((len = fis.read(buf)) != -1) {
//            fos.write(buf, 0, len);
//        }
//        fis.close();
//        fos.close();
//    }

    /**
     * 生成文件存储路径
     */
    public static String generatedFilePath() {

        return "";
    }

    /**
     * 根据文件id 获取到 文件的内容
     */
    public static String getContextTOMsgId() {

        return "";
    }

    public static void main(String[] args) throws Exception {

        FileUtil.nioWrite("D:\\testXml\\12.txt", 0, "UTF-8", "D:\\asd\\11\\12.txt");
    }

}
